/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#pragma once
#include <list>
#include <deque>
#include <vector>
#include <map>

#include "../shared/vector.h"
#include "Typedefs.h"

class IEntity;

// Brain Type
enum {
    BRAIN_RECKLESS,
    // ..
    BRAIN_NONE
};


/**
 * A tile an ent can move to
 */
struct PathNode
{   
	PathNode(Vector2f dest) { location = dest;};
	PathNode* entityPath;
    Vector2f location;
	float distanceFromGoal;
	bool isClosed;
};


/**
==================================
AI_Brain :: Interface for all brains to inherite from
==================================
*/
class AI_Brain
{
public:
	AI_Brain(void);
    /** Add a Entity to this Brain */
	void AddEntity(IEntity* ptr);
    /** Remove an Entity from this brain */
	void RemoveEntity( IEntity* ent );
    /** Remove all Entities */
    void RemoveAll();
    /** Cause the entities to think! */
    void ControlEntities();
    /** Retrieve this brains Identity */
	virtual int GetBrainType()=0;

public:
	virtual ~AI_Brain(void);
protected:
    /** Inherited Brains must overide this function */
    virtual void Think(IEntity* entPtr)=0;
    /** Patrol, using nav points */
	void ContinuePatrol(IEntity* entPtr);
    /** Check to see if this hasn't moved when it should have */
	void CheckStuck(IEntity* entPtr, const Vector2f &destination);

    /** Walk to an Entity */
	void GoToEntity(IEntity* entPtr, IEntity* destinationEntity );
    /** Walk to a location */
    void MoveTo(IEntity* ent, const Vector2f &destination); 

    /** Based off an enemy location, make this entity take cover from fire */
	Vector2f FindCover(IEntity* entPtr, IEntity* enemy);
    /** Run away from the enemy */
    void RunAway(IEntity* ent, IEntity* enemy);

    /** Check to see if this entity is close enough to a destination */
    bool CloseEnough(const Vector2f &dest, IEntity* entPtr);

    /** Check to see if an enemy is in your point of view */
    bool EnemyInView(int face, const Vector2f &enemyLoc, const Vector2f &entityLoc);


	void Pause(IEntity* entPtr);
	bool IsPaused(IEntity* entPtr);
	/**
        Data needed for ai to make decisions
    */
	struct AI_Data
	{
		//patrol data
		std::vector<Vector2f>   patrol;
		std::deque<Vector2f>    path;
		Vector2f                patrolVelocity;
		int	                    patrolIndex;

		//historical data
		Vector2f lastLocation;
		bool	 awareOfPlayer;
        bool     inRoute;   

		//various distances
		int sightRadius;
		int followDistance;
		int minRange;			//how close to get to the player before stopping / attacking
		int recalcDistance;		//how far off course you can get before recalculating your path

		//timing data
		float pauseTime;		//init to zero
		float pauseLength;
		
	};
	type_EntityLinkedList     entList;

    typedef std::map< IEntity*, AI_Data > type_EntityDataMap;
	type_EntityDataMap  m_dataTable;
private:
    /** Add a neighboring node */
	void AddNeighbor(std::list<PathNode> &openList, PathNode &entNode, IEntity* entPtr, const Vector2f destination, const Vector2f &offSet);
	/** Adds the neighbors of the current position into the open list if they are valid choices */
    void AddNeighbors(std::list<PathNode> &openList, PathNode &entNode, IEntity* entPtr, const Vector2f destination);
    /** Manuever this entity */
	void WalkTo(const Vector2f &current, const Vector2f &destination, IEntity* entPtr);
    /** Fill the path array with tiles to moveto from entPtr location to the destination */
	void FillPath(IEntity* entPtr, const Vector2f &destination, int pixelsAway);
    /** Determine if the entity can move here */
	bool LegalMove(IEntity* entPtr, Vector2f &testedVector);
};

